from asyncio.subprocess import Process
from typing import List, Optional
from fastapi.exceptions import HTTPException
from starlette.responses import JSONResponse
from core.item import BookItem, ItemState
from core.item_manager import ItemManager
from core.log import get_logger
from core.downloader import Downloader
from spider.baozimanhua import Spider
from .model import BookModel,ProgressModel
from fastapi import APIRouter,status



api_logger=get_logger('BookAPI')

router=APIRouter(tags=['book'])

@router.get('/books',response_class=JSONResponse,response_model=List[BookModel])
async def get_books(tag:str=None):
    if tag=='all':
        api_logger.debug('Client request for all books.')
        books= BookItem.select()
    elif tag=='downloading':
        api_logger.debug('Client request for downloading books.')
        books= BookItem.select().where(BookItem.state!=ItemState.Downloaded, BookItem.state!=ItemState.Temp)
    else:
        api_logger.debug('Unexpected request tag for books:'+str(tag)+', return defualt.')
        books=list(BookItem.select().where(BookItem.state>ItemState.Temp))
    # books= [Book(item) for item in bookItems]
    books=list(books)
    api_logger.debug(f'Return book item count:{len(books)}')
    return books

@router.get('/search',response_class=JSONResponse,response_model=List[BookModel])
async def search_books(keyword:str,limit:int=2):
    api_logger.debug('Accpept search request keyword:'+keyword)
    spider=Spider()
    books=spider.search(keyword,limit)
    api_logger.debug(f'Search book count:{len(books)}')
    return books
    # books= await get_books()
    # return books[:3]+[BookItem(id=-1,title='hello world',url='xyz',chapter_count=10,cover_url='xxx',state=ItemState.Temp)]

has_book_liking=False
@router.get('/like',response_model=BookModel)
async def like_book(book_id:int):
    global has_book_liking
    api_logger.debug('Accept like request book_id:'+str(book_id))
    if has_book_liking:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,detail='Please wait for current liking compeleted')
    try:
        spider=Spider()
        spider.update_book(BookItem.get_by_id(book_id))
        has_book_liking=False
        return BookItem.get_by_id(book_id)
    except Exception as e:
        raise
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,detail=str(e))

has_book_downloading=False

@router.get('/download')
async def download_book(book_id:int):
    global has_book_downloading
    if has_book_downloading:
        api_logger.warn('Current downloading is not completed!')
        raise HTTPException(status_code=400,detail='Please wait current book downloading to complete!')
    api_logger.debug('Accept download request, book id:'+str(book_id))
    # downloader=Downloader()
    # downloader.progress_changed_callback=notify_progress
    # downloader.download_book_async(book_id,download_completed)
    fake_download_async(book_id,progress_changed,download_completed)
    has_book_downloading=True
    return JSONResponse(status_code=200,content={"code":0})

def fake_download_async(bid,progress_callback,done_callback):
    from threading import Thread
    import time
    def run_fake():
        progress=0
        while progress<1:
            progress+=0.1
            api_logger.debug('Fake progress changed:'+str(progress))
            progress_callback(bid,progress)
            time.sleep(.2)
        api_logger.debug('Fake downloading done.')
        done_callback()
        
    Thread(target=run_fake).start()
    api_logger.debug('Fake downloading is running')


progress_model:ProgressModel=None

def progress_changed(book_id,progress):
    global progress_model
    progress_model=ProgressModel(book_id=book_id,value=progress)

def download_completed():
    global has_book_downloading
    has_book_downloading=False

@router.get("/progress",response_model=ProgressModel)
async def get_progress():
    global progress_model

    if progress_model:
        temp=progress_model
        progress_model=None
        return temp
    else:
        # return ProgressModel.empty_progress()
        return ProgressModel.empty_progress()

